using Consul;
using Microsoft.Extensions.Hosting;
using Microsoft.Extensions.Logging;
using Microsoft.Extensions.Options;

namespace Beauty.Net.Consul.Core;

/// <summary>
/// Consul服务注册托管服务
/// </summary>
public class ConsulHostedService : IHostedService, IDisposable
{
    private readonly ILogger<ConsulHostedService> _logger;
    private readonly ConsulOptions _options;
    private readonly IConsulClient _consulClient;
    private readonly CancellationTokenSource _cts = new();
    private string _serviceId = string.Empty;
    private bool _disposed;
    
    /// <summary>
    /// 构造函数
    /// </summary>
    public ConsulHostedService(
        ILogger<ConsulHostedService> logger,
        IOptions<ConsulOptions> options,
        IConsulClient consulClient)
    {
        _logger = logger;
        _options = options.Value;
        _consulClient = consulClient;
    }
    
    /// <summary>
    /// 启动服务注册
    /// </summary>
    public async Task StartAsync(CancellationToken cancellationToken)
    {
        if (!_options.EnableRegistration)
        {
            _logger.LogInformation("Consul服务注册已禁用");
            return;
        }
        
        try
        {
            // 生成服务ID
            _serviceId = !string.IsNullOrEmpty(_options.ServiceId) 
                ? _options.ServiceId 
                : $"{_options.ServiceName}-{Guid.NewGuid():N}";
            
            // 构建健康检查
            var healthCheckInterval = TimeSpan.FromSeconds(_options.HealthCheckInterval);
            var healthCheckTimeout = TimeSpan.FromSeconds(_options.HealthCheckTimeout);
            
            var healthCheck = new AgentServiceCheck
            {
                HTTP = $"{_options.ServiceAddress}:{_options.ServicePort}{_options.HealthCheckAddress}",
                Interval = healthCheckInterval,
                Timeout = healthCheckTimeout,
                DeregisterCriticalServiceAfter = TimeSpan.FromSeconds(30)
            };
            
            // 构建服务注册信息
            var registration = new AgentServiceRegistration
            {
                ID = _serviceId,
                Name = _options.ServiceName,
                Address = _options.ServiceAddress,
                Port = _options.ServicePort,
                Tags = _options.Tags.ToArray(),
                Check = healthCheck
            };
            
            // 注册服务
            await _consulClient.Agent.ServiceRegister(registration, cancellationToken);
            _logger.LogInformation("服务已成功注册到Consul: {ServiceId}", _serviceId);
            
            // 启动心跳检测
            _ = Task.Run(async () => await KeepAliveAsync(_cts.Token), _cts.Token);
        }
        catch (Exception ex)
        {
            _logger.LogError(ex, "服务注册到Consul失败");
            throw;
        }
    }
    
    /// <summary>
    /// 心跳检测
    /// </summary>
    private async Task KeepAliveAsync(CancellationToken cancellationToken)
    {
        while (!cancellationToken.IsCancellationRequested)
        {
            try
            {
                var interval = TimeSpan.FromSeconds(_options.HealthCheckInterval);
                await Task.Delay(interval / 2, cancellationToken);
                
                // 更新服务TTL
                await _consulClient.Agent.PassTTL($"service:{_serviceId}", "Service is alive", cancellationToken);
            }
            catch (TaskCanceledException)
            {
                // 任务取消，正常退出
                break;
            }
            catch (Exception ex)
            {
                _logger.LogWarning(ex, "心跳检测失败");
            }
        }
    }
    
    /// <summary>
    /// 停止服务
    /// </summary>
    public async Task StopAsync(CancellationToken cancellationToken)
    {
        if (!_options.EnableRegistration || string.IsNullOrEmpty(_serviceId))
        {
            return;
        }
        
        try
        {
            // 取消心跳任务
            _cts.Cancel();
            
            // 注销服务
            await _consulClient.Agent.ServiceDeregister(_serviceId, cancellationToken);
            _logger.LogInformation("服务已从Consul注销: {ServiceId}", _serviceId);
        }
        catch (Exception ex)
        {
            _logger.LogError(ex, "服务从Consul注销失败");
        }
    }
    
    /// <summary>
    /// 释放资源
    /// </summary>
    public void Dispose()
    {
        Dispose(true);
        GC.SuppressFinalize(this);
    }
    
    /// <summary>
    /// 释放资源
    /// </summary>
    protected virtual void Dispose(bool disposing)
    {
        if (!_disposed)
        {
            if (disposing)
            {
                _cts.Cancel();
                _cts.Dispose();
            }
            
            _disposed = true;
        }
    }
}